﻿#pragma execution_character_set("utf-8")
#include "btosg.h"
#include <osg/Material>
#include <osg/Texture2D>
#include <QtMath>
#define _DEBUG_ (0)

void btosgObject::print()
{
    std::cout << "Object: " << name << "\n";
    btosgVec3 pos = getPosition();

    std::cout << "  Position: " << pos.x() << ", " << pos.y() << ", " << pos.z() << "\n";
    if ( isnan(pos.x() )) exit(2);
}

void btosgObject::setTexture(const char *fname)
{
    /// Sets the object texture from a loaded image file.

    osg::StateSet * stateset=new osg::StateSet;

    osg::ref_ptr<osg::Image> image=osgDB::readRefImageFile(fname);
    if(image){
        //这里创建一个纹理对象
        osg::Texture2D * texture=new osg::Texture2D;
        //设置图像为纹理图像：
        texture->setImage(image);
        //设置过滤的方式和过滤的时机
        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
        //将纹理对象设置到状态集合中的纹理单元
        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);

    }

    //设置光照
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON);
    //全部设置完了之后，就把添加进去，这里只能由一个状态集，所以是set
    model->setStateSet(stateset);



}

/**
 * @brief btosgObject::reset
 * 重置的话，也是和设置rotation这些一样，主要就是body控制五个东西 世界坐标，运动坐标，受力，线性速度，角速度，
 * 这里还有一个激活的active
 *
 * 然后模型这里，需要设置position和attribute(这里就是旋转的四元矩阵)
 */
void btosgObject::reset()
{
    /// Reposition object to its inital state.
    ///
    if(this->body){
        body->setWorldTransform(init_state);
        body->getMotionState()->setWorldTransform(init_state);
        body->clearForces();
        if(this->mass){
            body->setAngularVelocity(btVector3(0.,0.,0.));
            body->setLinearVelocity(btVector3(0.,0.,0.));
            body->activate();
        }
    }else{
        if(model){
            model->setAttitude(btosgQuat(init_state.getRotation()));
            model->setPosition(btosgVec3(init_state.getOrigin()));

        }
    }



}

/**
 * @brief btosgObject::createRigidBody
 * 穿件刚体要有四个参数 重点
 * mass质量
 * inertia 惯性
 * shape 形状
 * motionState 运动状态
 */
void btosgObject::createRigidBody()
{
     /// Creates a new rigid body as a btRigidBody object.
    if(!this->shape){
        fprintf(stderr,"Cannot create RigidBody without shape\n");
        return;
    }
    btDefaultMotionState *mState=new btDefaultMotionState;
    btVector3 inertia(0,0,0);
    shape->calculateLocalInertia(mass,inertia);
    btRigidBody::btRigidBodyConstructionInfo cinfo=btRigidBody::btRigidBodyConstructionInfo(mass,mState,shape,inertia);
    cinfo.m_restitution=0.9f;
    cinfo.m_friction=10.f;
    body=new btRigidBody(cinfo);

    if(!this->body){
        fprintf(stderr,"Error creating btBody\n");
    }


}

//这个主要用来加载模型，但是好像没有用到
void btosgObject::loadObjectModel(const char *fname)
{
    /// Loads an object model from a Wavefront OBJ file.
    /// Loadded model is used to define both the collision and graphical shapes.
    if ( ! fname || ! *fname ) {
        fprintf(stderr,"Invalid object model filename\n");
        return;
    }

    osg::Node* loadedModel = osgDB::readNodeFile(fname);
    if ( ! loadedModel ) {
        fprintf(stderr,"Error reading Object model from file '%s'\n", fname);
    }

    if ( name ) {
    fprintf(stderr,"Warning: Object '%s' overloaded with object '%s'\n", name, fname);
    }

    setName(fname);
    //PositionAttitudeTransform就是方位 平移 旋转 转化节点
    if ( ! model )	model = new osg::PositionAttitudeTransform;
    osg::PositionAttitudeTransform* obj_rot = new osg::PositionAttitudeTransform;
    //这个设置了没啥用
    obj_rot->setAttitude(osg::Quat(-osg::PI/2,osg::Vec3(1.,0.,0.)));
    obj_rot->addChild(loadedModel);
    model->addChild(obj_rot);





}







/**
* @brief btosgWorld::removeObject
* 从
* @param obj
*/


void btosgWorld::removeObject(btosgObject *obj)
{
    if(obj->body){
        dynamic->removeRigidBody(obj->body);
    }else if ( _DEBUG_ ) fprintf(stderr,"Removing object without rigid body\n");
    if(obj->model){
        scene->removeChild(obj->model);
    } else if ( _DEBUG_ ) fprintf(stderr,"Removing object without visual model\n");
    // Remove from the list.
    // This also calls de the destructor for obj.
    this->objects.remove(obj);

}



int btosgWorld::deleteAllObjects()
{
    int count=0;
    while (!this->objects.empty()) {
        btosgObject *obj=objects.front();
        //单个移除
        this->removeObject(obj);
        delete(obj);
            //std::cout << ' ' << mylist.front();
            count++;
    }
    return count;

}

void btosgWorld::reset()
{
    /// Reset all registered objects.
    for ( auto it = objects.begin(); it != objects.end(); ++it ) {
        btosgObject *obj = *it;
        obj->reset();
    }



}

btosgWorld::~btosgWorld()
{
    this->deleteAllObjects();

    delete (this->dynamic);
    delete this->solver;
    delete this->broadphase;
    delete this->dispatcher;
    delete this->collisionConfiguration;
    //scene有自动回收机制




}


void btosgWorld::stepSimulation(btScalar timeStep, int maxSubSteps)
{
     /// Performs a simulation step.
    if(this->steps==0L){
        for(auto it = objects.begin();it != objects.end();it++){
            btosgObject *obj=*it;
            //body的位置初始化了
            obj->setInitState();
        }

    }
//    std::cout<<u8"e i want to see i can execute times"<<std::endl;


    if(this->dynamic){
//        std::cout<<u8"exit"<<std::endl;
//        this->dynamic->stepSimulation(timeStep,maxSubSteps);
        this->dynamic->stepSimulation(0.1,maxSubSteps);

    }else{
        std::cout<<u8"no--exit"<<std::endl;
    }

//    设置模型
    //
//    std::cout<<u8"ga ga ga ga"<<std::endl;
    for(auto it=objects.begin();it !=objects.end();it++){
        btosgObject *obj = *it;
        obj->update();
    }
    steps += 1;

}


/**
 * @brief btosgWorld::addObject
 * 添加进去一个物体，同时具有刚体和可视化的模型
 * @param obj
 *
 */
void btosgWorld::addObject(btosgObject *obj)
{
    /// Registers the object obj into a simulation world.
    objects.push_front(obj);
    this->objects.push_front(obj);
    if(obj->body){
        dynamic->addRigidBody(obj->body);
    }else if ( _DEBUG_ ) fprintf(stderr,"Adding object without rigid body\n");


    if(obj->model){
        this->scene->addChild(obj->model);
    } else if ( _DEBUG_ ) fprintf(stderr,"Adding object without visual model\n");

}

void btosgWorld::listObjects()
{
    int n=0;
    printf("## Object List\n");
    for(auto it=objects.begin();it!=objects.end();it++){
        btosgObject *obj=*it;
        obj->print();
        n++;
    }
    printf("%d objects listed.\n",n);



}









